<?php

namespace App\Kuafu\Order\Service;


use App\Exceptions\BaseException;
use App\Kuafu\Coupon\Exceptions\CouponException;
use App\Kuafu\Coupon\Service\CouponService;
use App\Kuafu\CouponExt\Channel\CouponExtBase;
use App\Kuafu\CouponExt\Channel\DouYin\DouyinCouponBase;
use App\Kuafu\CouponExt\Enum\CouponExtCodeEnum;
use App\Kuafu\CouponExt\Enum\CouponExtEnum;
use App\Kuafu\CouponExt\Exceptions\CouponExtException;
use App\Kuafu\CouponExt\Model\OrderCouponExtSplitModel;
use App\Kuafu\Order\Enum\OrderInfoEnum;
use App\Kuafu\Shop\Service\ShopService;
use App\Library\SnowFlake\SnowFlake;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use function Symfony\Component\String\s;

class OrderCouponExternalService extends OrderBaseSplitService
{
    public int $couponExtPlatform = 0; // 平台类型

    public function __construct(int $couponExtPlatform, int $shopId = 0, int $brandId = 0, int $orderId = 0)
    {
        $this->couponExtPlatform = $couponExtPlatform;
        parent::__construct($brandId, $shopId, $orderId);
    }

    /**
     * 切换 pos 的支付方式转为三方平台
     *
     * @param int $posPayment
     * @return void
     */
    public function resetCouponExtPlatformByPosPayment(int $posPayment)
    {
        switch ($posPayment) {
            case OrderInfoEnum::POS_ORDER_PAYMENT_COUPON:
            case OrderInfoEnum::POS_ORDER_PAYMENT_COUPON_MEITUAN:
                $this->couponExtPlatform = CouponExtEnum::EXT_PLATFORM_MEITUAN;
                break;
            case OrderInfoEnum::POS_ORDER_PAYMENT_COUPON_DOUYIN:
                $this->couponExtPlatform = CouponExtEnum::EXT_PLATFORM_DOUYIN;
                break;
            case OrderInfoEnum::POS_ORDER_PAYMENT_COUPON_XHS:
                $this->couponExtPlatform = CouponExtEnum::EXT_PLATFORM_XHS;
                break;
            default:
                $this->couponExtPlatform = CouponExtEnum::EXT_PLATFORM_MEITUAN;
        }
    }

    /**
     * 获取优惠券信息
     *
     * @throws GuzzleException
     * @throws CouponExtException|BaseException
     * @throws \Exception
     */
    public function getCouponExtInfo(string $code, bool $needCheckCanUseProduct = false)
    {
        $couponPrepare = CouponExtBase::getIns($this->shopId, $this->couponExtPlatform)->couponPrepare($code);

        self::throwOutExtCoupon($couponPrepare, $this->couponExtPlatform);

        $couponPrepareData = $couponPrepare['data'];

        // 获取 三方优惠券 对应的商品数据

        if ($needCheckCanUseProduct && !empty($couponPrepareData['skuId'])) {
            // 判断是否是单菜
            if (is_numeric($couponPrepareData['canUseProduct']) || empty($couponPrepareData['canUseProduct'])) {
                $canUseProductId                    = CouponExtBase::getCanUseProductBySkuId($this->couponExtPlatform,
                    $couponPrepareData, $this->shopId);
                $couponPrepareData['canUseProduct'] = $canUseProductId;
            }

            $couponPrepareData['canUseProducts'] = CouponExtBase::getCanUseProductsBySkuId($this->couponExtPlatform,
                $couponPrepareData, $this->shopId);
        }

        return $couponPrepareData;
    }

    /**
     * 核销三方优惠券
     *
     * @param string $couponCode
     * @param int $consumeNum
     * @param int $couponDiscountPrice
     * @return array
     * @throws CouponExtException
     * @throws GuzzleException|BaseException
     */
    public function consumeCouponExt(
        string $couponCode,
        int $consumeNum,
        int $couponDiscountPrice,
        array $customData = []
    ): array {
        $couponPrepare = self::getCouponExtInfo($couponCode, true);


        $couponNum      = $couponPrepare['count'];
        $couponType     = $couponPrepare['couponType'];
        $userPay        = $couponPrepare['userPay'];
        $deduction      = $couponPrepare['deduction'];
        $minConsume     = $couponPrepare['minConsume'];
        $couponTitle    = $couponPrepare['couponTitle'];
        $canUseProduct  = $couponPrepare['canUseProduct'] ?? '';// 原单个菜
        $canUseProducts = $couponPrepare['canUseProducts'] ?? [];// 券内多个套餐菜详情

        // 可核销数量不足
        if ($couponNum < $consumeNum) {
            throw new CouponExtException(CouponExtCodeEnum::ERR_MEITUAN_COUPON_NUM, $couponPrepare['msg']);
        }

        // 未达到最低核销数量
        if ($minConsume > $consumeNum) {
            throw new CouponExtException(CouponExtCodeEnum::ERR_MEITUAN_COUPON_MIN_NUM, $couponPrepare['msg']);
        }

        // 核销
        $couponConsume = CouponExtBase::getIns($this->shopId, $this->couponExtPlatform)
                                      ->couponConsume($couponPrepare['couponCode'], $consumeNum, $this->orderId);

        if (!$couponConsume['status']) {
            throw new CouponExtException(CouponExtCodeEnum::ERR_MEITUAN_COUPON_CONSUME, $couponConsume['msg']);
        }

        $couponCodes = $couponConsume['data']['couponCodes'];
        $couponSid   = $couponConsume['data']['couponSid'];

        $couponConsume['oriData']['canUseProduct']  = $canUseProduct;
        $couponConsume['oriData']['canUseProducts'] = $canUseProducts;
        $couponConsume['oriData']['customData']     = $customData;

        $insertData = [];

        foreach ($couponCodes as $couponCode) {

            $productCouponDiscount = $couponConsume['oriData']['customData']['useProducts']['deduction'] ?? 0;

            if ($productCouponDiscount) {
                $discount = (int)$productCouponDiscount;
            } else {
                if ($couponDiscountPrice > $deduction) {
                    $discount            = $deduction;
                    $couponDiscountPrice -= $deduction;
                } else {
                    $discount = $couponDiscountPrice;
                }
            }

            $insertData[] = [
                'id'                        => SnowFlake::nextIdCache(),
                'brandId'                   => $this->brandId,
                'shopId'                    => $this->shopId,
                'orderId'                   => $this->orderId,
                'extPlatform'               => $this->couponExtPlatform,
                'couponExtSid'              => $couponSid,
                'couponExtCode'             => $couponCode['couponCode'],
                'couponExtName'             => $couponTitle,
                'couponExtType'             => $couponType,
                'couponExtCostPrice'        => $userPay,
                'couponExtDiscountPrice'    => $discount,
                'couponExtMaxDiscountPrice' => $deduction,
                'couponExtStatus'           => CouponExtEnum::COUPON_STATUS_USED,
                'couponExtCodeData'         => json_encode($couponConsume['oriData'], JSON_UNESCAPED_UNICODE),
                // 核销完成之后的返回数据
                'createdAt'                 => time(),
                'updatedAt'                 => time(),
            ];
        }

        // 批量入库
        OrderCouponExtSplitModel::suffix($this->shopId)->batchAddData($insertData);

        return $insertData;
    }


    /**
     * 核销三方优惠券
     *
     * @param string $couponCode
     * @param int $consumeNum
     * @param int $couponDiscountPrice
     * @return array
     * @throws CouponExtException
     * @throws GuzzleException
     */
    public function consumeCouponExtDouyinApplet(string $couponCode, int $consumeNum, int $couponDiscountPrice): array
    {
        $couponPrepare = self::getCouponExtInfo($couponCode, true);

        $couponNum   = $couponPrepare['count'];
        $couponType  = $couponPrepare['couponType'];
        $userPay     = $couponPrepare['userPay'];
        $deduction   = $couponPrepare['deduction'];
        $minConsume  = $couponPrepare['minConsume'];
        $couponTitle = $couponPrepare['couponTitle'];

        // 可核销数量不足
        if ($couponNum < $consumeNum) {
            throw new CouponExtException(CouponExtCodeEnum::ERR_MEITUAN_COUPON_NUM, $couponPrepare['msg']);
        }

        // 未达到最低核销数量
        if ($minConsume > $consumeNum) {
            throw new CouponExtException(CouponExtCodeEnum::ERR_MEITUAN_COUPON_MIN_NUM, $couponPrepare['msg']);
        }

        // 核销
        $couponConsume = CouponExtBase::getIns($this->shopId, $this->couponExtPlatform)
                                      ->buildCouponConsume($couponPrepare, $consumeNum);
        $couponCodes   = $couponConsume['data']['couponCodes'];
        $couponSid     = $couponConsume['data']['couponSid'];
        $insertData    = [];

        foreach ($couponCodes as $couponCode) {
            if ($couponDiscountPrice > $deduction) {
                $discount            = $deduction;
                $couponDiscountPrice -= $deduction;
            } else {
                $discount = $couponDiscountPrice;
            }

            $insertData[] = [
                'id'                        => SnowFlake::nextIdCache(),
                'brandId'                   => $this->brandId,
                'shopId'                    => $this->shopId,
                'orderId'                   => $this->orderId,
                'extPlatform'               => $this->couponExtPlatform,
                'couponExtSid'              => $couponSid,
//                'couponExtCode'             => $couponCode['couponCode'],
                'couponExtCode'             => '',
                'couponExtName'             => $couponTitle,
                'couponExtType'             => $couponType,
                'couponExtCostPrice'        => $userPay,
                'couponExtDiscountPrice'    => $discount,
                'couponExtMaxDiscountPrice' => $deduction,
//                'couponExtStatus'           => CouponExtEnum::COUPON_STATUS_DEFAULT,
                'couponExtStatus'           => CouponExtEnum::COUPON_STATUS_USED,
                'createdAt'                 => time(),
                'updatedAt'                 => time(),
            ];
        }

        // 批量入库
        OrderCouponExtSplitModel::suffix($this->shopId)->batchAddData($insertData);

        return $insertData;
    }

    /**
     * 撤销优惠券
     *
     * @param string $couponCode
     * @return array
     * @throws CouponExtException
     * @throws GuzzleException
     */
    public function cancelCouponByOrder(string $couponCode): array
    {
        $couponList = OrderCouponExtSplitModel::suffix($this->shopId)
                                              ->getCouponsByOrderId($this->getOrderId(true),
                                                  CouponExtEnum::COUPON_STATUS_USED, $couponCode)
                                              ->unique('couponExtCode');

        foreach ($couponList as $couponInfo) {
            $cancelCouponInfo = [
                'couponExtCode'     => $couponInfo['couponExtCode'],
                'couponExtCodeData' => $couponInfo['couponExtCodeData'],
            ];

            $cancel = CouponExtBase::getIns($couponInfo['shopId'], $this->couponExtPlatform)
                                   ->couponCancel($cancelCouponInfo);
            if (!$cancel['status']) {
                throw new CouponExtException(CouponExtCodeEnum::ERR_MEITUAN_COUPON_CANCEL, $cancel['msg']);
            }

            // 更新
            OrderCouponExtSplitModel::suffix($this->shopId)
                                    ->cancelCoupon($this->getOrderId(true), $couponInfo['couponExtCode']);
        }

        return $couponList->pluck('couponExtCode')->toArray();
    }

    /**
     * 切换抖音的券类型匹配成系统券类型
     *
     * @param int $dyType
     * @return int
     */
    public static function toggleDyCouponType(int $dyType): int
    {
        switch ($dyType) {
            case 1:
                return CouponExtEnum::COUPON_TYPE_GROUP_MEALS;
            case 3:
                return CouponExtEnum::COUPON_TYPE_TIMES_CARD;
            case 2:
            default:
                return CouponExtEnum::COUPON_TYPE_MONEY;
        }
    }

    /**
     * 切换收银支付方式到三方平台优惠券
     *
     * @param string|int $paymentCoupon
     * @return int
     */
    public static function togglePosCouponTypeToCouponType($paymentCoupon): int
    {
        // 为了兼容以前的代码 留个口子
        switch ($paymentCoupon) {
            case OrderInfoEnum::POS_ORDER_PAYMENT_COUPON:
            case OrderInfoEnum::POS_ORDER_PAYMENT_COUPON_MEITUAN:
                return CouponExtEnum::EXT_PLATFORM_MEITUAN;
            case OrderInfoEnum::POS_ORDER_PAYMENT_COUPON_DOUYIN:
                return CouponExtEnum::EXT_PLATFORM_DOUYIN;
            default:
                return 0;
        }
    }

    /**
     * 计算总价/总次数, 使用次数,平均金额 (正算)
     *
     * @param int $total
     * @param int $timesCount
     * @param int $itemsUsed
     * @return int|string|null
     */
    private static function calcUnitVerifyPrice(int $total, int $timesCount, int $itemsUsed = 1)
    {
        $remainNum   = $total % $timesCount;
        $intAvgPrice = bcdiv($total, $timesCount);

        if ($itemsUsed >= $timesCount) {
            return 0;
        }

        $returnAvgPrice = $intAvgPrice;
        if ($total % $timesCount && $remainNum > $itemsUsed) {
            //  计算余数是否小于当前已使用次数, 如果小于+1, 否则正常取整
            $returnAvgPrice = bcadd($returnAvgPrice, 1);
        }

        return $returnAvgPrice;
    }

    /**
     * 计算总价/总次数, 使用次数,平均金额 (反算)
     *
     * @param int $total
     * @param int $timesCount
     * @param int $itemsUsed
     * @return int|string|null
     */
    public static function calcUnitVerifyPriceReverse(int $total, int $timesCount, int $itemsUsed = 1)
    {
        $remainNum   = $total % $timesCount;
        $intAvgPrice = bcdiv($total, $timesCount);

        if ($itemsUsed >= $timesCount) {
            return 0;
        }

        $returnAvgPrice = $intAvgPrice;
        if ($total % $timesCount && $remainNum >= ($timesCount - $itemsUsed)) {
            //  计算余数是否小于当前已使用次数, 如果小于+1, 否则正常取整
            $returnAvgPrice = bcadd($returnAvgPrice, 1);
        }

        return $returnAvgPrice;
    }

    /**
     * 通过 抖音 code 获取抖音券信息 [无用]
     *
     * @param int $shopId
     * @param string $code
     * @return array|array[]
     */
    public static function getDouYinCouponInfoByCode(int $shopId, string $code)
    {
        $dyModel    = new DouyinCouponBase(0, $shopId);
        $couponInfo = $dyModel->couponPrepareCode($code);

        if (!$couponInfo['status']) {
            return $couponInfo;
        }

        $oriData      = $couponInfo['oriData']['certificates'][0];
        $kfCouponType = self::toggleDyCouponType($oriData['sku']['groupon_type'] ?? 0);

        return [
            [
                // 关联张数，最大可验证张数
                'count'           => 1,
                // 券的关联id
                'couponSid'       => '',
                // 券名称
                'couponTitle'     => $oriData['sku']['title'],
                // 券码
                'couponCode'      => $oriData['encrypted_code'],
                // 券类型
                'couponType'      => $kfCouponType,
                // 用户支付的钱
                'userPay'         => $oriData['amount']['coupon_pay_amount'],
                // 可抵扣的钱
                'deduction'       => $oriData['sku']['market_price'],
                // 券可开始使用时间
                'couponBeginTime' => $oriData['sku']['sold_start_time'],
                // 券使用截止日期
                'couponEndTime'   => $oriData['expire_time'],
                // 最小消费张数
                'minConsume'      => 1,
                // 菜单列表
                'dealMenu'        => [],
            ]
        ];
    }


    /**
     * 快速查券
     *
     * @param int $shopId
     * @param string $couponCode
     * @param int $couponFrom
     * @return array
     * @throws BaseException
     * @throws CouponExtException
     * @throws GuzzleException
     */
    public static function quickAllCoupon(int $shopId, string $couponCode, int $couponFrom = -1): array
    {
        if ($couponFrom >= 0) {
            // 指定平台查券
            return self::getCouponDataByType($shopId, $couponCode, $couponFrom);

        }
        // 按规则查券
        $isKf = true;
        $isMt = true;
        $isDy = true;

        // 判断是否是 url, 只可能是抖音也不用查其他情况
        if (DouyinCouponBase::checkDyUrl($couponCode)) {
            $data = OrderCouponExternalService::getExtCouponNoThrow(CouponExtEnum::EXT_PLATFORM_DOUYIN, $couponCode,
                $shopId);

            if (empty($data)) {
                throw new CouponExtException(CouponExtCodeEnum::ERR_COUPON_NOT_FOUND);
            }

            return $data;
        }

        // 判断 12 位券码是美团
        if (strlen($couponCode) == 12) {
            $data = OrderCouponExternalService::getExtCouponNoThrow(CouponExtEnum::EXT_PLATFORM_MEITUAN,
                $couponCode,
                $shopId);
            if (!empty($data)) {
                return $data;
            }
            $isMt = false;
        }

        // 判断券码是否是夸父券
        if (self::isKfCoupon($couponCode)) {
            $data = OrderCouponExternalService::getKfCouponNoThrow($couponCode, $shopId);
            if (!empty($data)) {
                return $data;
            }
            $isKf = false;
        }

        // 最后过滤一遍所有情况 - 夸父
        if ($isKf) {
            $data = OrderCouponExternalService::getKfCouponNoThrow($couponCode, $shopId);
            if (!empty($data)) {
                return $data;
            }
        }

        // 判断是否是抖音券码
        if ($isDy) {
            $data = OrderCouponExternalService::getExtCouponNoThrow(CouponExtEnum::EXT_PLATFORM_DOUYIN, $couponCode,
                $shopId);
            if (!empty($data)) {
                return $data;
            }
        }

        // 判断是否是美团
        if ($isMt) {
            $data = OrderCouponExternalService::getExtCouponNoThrow(CouponExtEnum::EXT_PLATFORM_MEITUAN,
                $couponCode,
                $shopId);
            if (!empty($data)) {
                return $data;
            }
        }

        throw new CouponExtException(CouponExtCodeEnum::ERR_COUPON_NOT_FOUND);
    }


    /**
     * 查券处理
     *
     * @throws GuzzleException
     * @throws CouponException
     * @throws BaseException
     * @throws CouponExtException
     */
    public static function getCouponDataByType(int $shopId, string $couponCode, int $couponType): array
    {
        switch ($couponType) {
            case CouponExtEnum::EXT_PLATFORM_KUAFU:
                return (new CouponService(0, $shopId))->getKfCouponInfo($couponCode);
            case CouponExtEnum::EXT_PLATFORM_MEITUAN:
            case CouponExtEnum::EXT_PLATFORM_DOUYIN:
                return (new OrderCouponExternalService($couponType, $shopId))->getCouponExtInfo($couponCode, true);
            default:
                throw new CouponExtException(CouponExtCodeEnum::ERR_COUPON_NOT_FOUND);
        }
    }


    protected static function isKfCoupon(string $couponCode): bool
    {
        return strlen($couponCode) == 14 && strpos($couponCode, '100') === 0;
    }


    /**
     * @param string $couponCode
     * @return array
     */
    public static function getKfCouponNoThrow(string $couponCode, int $shopId): array
    {
        try {
            $data = (new CouponService(0, $shopId))->getKfCouponInfo($couponCode);
            return $data;
        } catch (\Exception $exception) {
            return [];
        }
    }

    public static function getExtCouponNoThrow(int $couponType, string $couponCode, int $shopId)
    {
        try {
            $model = new OrderCouponExternalService($couponType, $shopId);
            $data  = $model->getCouponExtInfo($couponCode, true);
            return $data;
        } catch (\Exception $exception) {
            Log::channel('order')->error('优惠券查询失败', [
                'shopId'     => $shopId,
                'couponType' => $couponType,
                'couponCode' => $couponCode,
                'errMsg'     => $exception->getMessage()
            ]);
            if (in_array($exception->getCode(), self::getCanThrowOutCode())) {
                throw $exception;
            }
            return [];
        }
    }

    /**
     * 能异常报错的提示
     *
     * @return array
     */
    public static function getCanThrowOutCode(): array
    {
        return [
            CouponExtCodeEnum::ERR_COUPON_PLATFORM_NOT_SUIT,
            CouponExtCodeEnum::ERR_MEITUAN_CONFIG_EMPTY,
            CouponExtCodeEnum::ERR_DOUYIN_CONFIG_EMPTY,
        ];
    }


    /**
     * 针对每个平台提示报错
     *
     * @param array $couponPrepare
     * @param $couponExtPlatform
     * @return void
     * @throws CouponExtException
     */
    public function throwOutExtCoupon(array $couponPrepare, $couponExtPlatform)
    {
        if (empty($couponPrepare) || (!$couponPrepare['status'])) {
            // 抖音报错异常处理
            $errCode  = $couponPrepare['code'] ?? 0;
            $shopInfo = ShopService::getShopInfo($this->shopId);
            switch ($errCode) {
                case 3001:
                    // 判断是否是美团的报错 // 券不属于该分店，不能接待。请确认是否选择正确门店，或与顾客确认该券的可用门店。
                    if ($couponExtPlatform == CouponExtEnum::EXT_PLATFORM_MEITUAN) {
//                        throw new CouponExtException(CouponExtCodeEnum::ERR_COUPON_PLATFORM_NOT_SUIT,
//                            CouponExtEnum::EXT_PLATFORM_TEXT[$couponExtPlatform] . '优惠券不属于该分店。请确认是否选择正确门店，或与顾客确认该券的可用门店。');
                        throw new CouponExtException(CouponExtCodeEnum::ERR_COUPON_PLATFORM_NOT_SUIT,
                            "此券无法在当前门店（{$shopInfo->shortName}）使用，请用户尝试退券后重新购买新券");
                    }

                    throw new CouponExtException(CouponExtCodeEnum::ERR_COUPON_PLATFORM_NOT_SUIT,
                        CouponExtEnum::EXT_PLATFORM_TEXT[$couponExtPlatform] . $couponPrepare['msg']);

                case 3000001:
                    throw new CouponExtException(CouponExtCodeEnum::ERR_MEITUAN_COUPON_PREPARE,
                        CouponExtEnum::EXT_PLATFORM_TEXT[$couponExtPlatform] . $couponPrepare['msg']);
                    break;
                default:
                    throw new CouponExtException(CouponExtCodeEnum::ERR_MEITUAN_COUPON_PREPARE,
                        CouponExtEnum::EXT_PLATFORM_TEXT[$couponExtPlatform] . '优惠券券码有误，请刷新二维码重试。');
            }
        }
    }
}
